<!-- Last Updated: Friday May 31, 2002 Version 0.7-->
<html>
  <head>
    <title>SAX for Pascal Demo - Choosing a parser from a list of available parsers</title>
  </head>
  <body>
    <div width="100%" align="right">
      <a href="http://xml.defined.net/SAX/">SAX for Pascal Home</a>
      &#160;
      <a href="http://xml.defined.net/SAX/docs">SAX for Pascal Documentation</a>
    </div>
    <h1>Choosing a Parser from a List</h1>
    <p>This demo is intended to show you how you can fill a
    list with all of the available parsers. In addition it shows the
    basics of checking the features of an XMLReader. This demo does
    not include any information about parsing. For more information
    about parsing, please see the Simple Parsing Demo.</p>
    <h2>Adding the parsers to the project</h2>
    <p>In order to fill the list with parsers you must
    first make sure that there are available parsers within
    your project. To do this, you must add the files to the
    Project. <i>(The technical reasons behind this are simple,
    the initialization code for each parser package must be called.
    By adding the unit to the project you can be sure that the
    project will execute the code in the package's initialization
    section)</i></p>
    <p>First click "<code>Project | Add To Project</code>" on the
    file menu. In this demo you should see that SAXKW and SAXMS
    have already been added for you. This allows you to use
    either of the default parsers provided by Keith Wood. You
    can add another parser by including the unit that declares
    that package's vendor information.</p>
    <h2>Filling the lists</h2>
    <p>Now that you have some available SAX parsers you will want
    to add some code to fill a list. In this demo our list is a
    TComboBox string list. We will need to include the <code>SAX</code>
    unit in the uses clause. Then we can just add the code to the FormCreate.
    First we fill the list, then we select the DefaultSAXVendor.</p>
    <p>
      <pre>
        // Fill the list
        ListSAXVendors(ComboBox1.Items);
        // Set the item index
        ComboBox1.ItemIndex:= ComboBox1.Items.IndexOf(DefaultSAXVendor);
      </pre>
    </p>
    <p>Remember the DefaultSAXVendor is a SAXString so we must look it up by
    it's index in the ComboBox rather than simply setting the ItemIndex.</p>
    <h2>Getting information about each parser</h2>
    <p>Now that we have code to fill the list with the available parsers, we
    will add an <code>OnChange</code> event to the our TComboBox so that
    we can see the features of each parser's XMLReader. This demo
    shows which features are turned on by default. If a specific feature
    is not supported it will show "Not Supported". Checking certain features
    may not be supported at different times (e.g. when parsing or
    when not parsing) but may be supported at other times.</p>
    <p>It is important to be aware that in SAX for Pascal there are two
    kinds of Vendors: Normal and Buffered. A <i>Buffered</i> Vendor is
    a vendor that is relying on the Buffered (or PSAXChar) versions of the
    interfaces, such as IBufferedXMLReader. Generally these parsers are much
    faster because they require fewer string allocations. A good example of
    a Buffered SAX vendor is <a href="http://xml.defined.net/SAX/expat">KDSSAXExpat</a>.
    </p>
    <p>We begin by adding the event, then we will try to get information
    about the Vendor and XMLReader itself. Essentially we must begin by
    getting the Vendor and accessing the Description or XMLReader:</p>
    <p>
      <pre>
        // Get the vendor
        AVendor:= GetSAXVendor(ComboBox1.Items[ComboBox1.ItemIndex]);

        // Get the description
        labDesc.Caption:= AVendor.Description;

        // Get the XML Reader
        Buffered:= AVendor is TBufferedSAXVendor;
        if Buffered then
          AXMLReader:= TBufferedSAXVendor(AVendor).BufferedXMLReader
        else
          AXMLReader:= AVendor.XMLReader;
      </pre>
    </p>
    <p>Again, we are checking what kind of Vendor we have. If it is a
    TBufferedXMLReader, we will access the BufferedXMLReader property.
    Once we have the XMLReader we can check its features. We must be careful
    however if a feature is not recognized the XMLReader will raise an
    <code>ESAXNotRecognizedException</code>. In some cases a checking property
    might not be supported when parsing or when not parsing. If checking
    a feature (or setting a feature) is not supported at a given time
    the XMLReader will raise an <code>ESAXNotSupportedException</code> exception.
    Because of this, it is safest to wrap this code in a <code>try..except</code>
    block:</p>
    <p>
      <pre>
        try
          // Check for the feature
          if GetFeature(ValidationFeature, AXMLReader, Buffered) then
            labVal.Caption:= 'Yes'
          else
            labVal.Caption:= 'No';
        except
          on e : ESAXNotRecognizedException do
          begin
            // The XMLReader didn't recognize the feature
            labVal.Caption:= 'Not recognized'
          end;
          on e2 : ESAXNotSupportedException do
          begin
            // The XMLReader doesn't support querying this feature right now
            labVal.Caption:= 'Not supported'
          end;
        end;
      </pre>
    </p>
    <p>This will keep the exception from showing in the application. Instead it
    will only show when you are debugging the application in Delphi.
    You can also set features this way. Again, you need to be careful that the
    feature is recognized and supported.</p>
    <p>Notice that we used the function GetFeature. You may be wondering what
    that function does. All it does is provide an easy way to check the feature
    of either a normal or Buffered XMLReader:</p>
    <p>
      <pre>
        function GetFeature(Feature: SAXString; XMLReader: IUnknown;
          Buffered: Boolean): Boolean;
        begin
          if Buffered then
            Result:= IBufferedXMLReader(XMLReader).Features[Feature]
          else
            Result:= IXMLReader(XMLReader).Features[Feature];
        end;
      </pre>
    </p>
    <p>Features in SAX are identified by URLs. However, this does not mean that
    you can type a feature URL in the browser and look it up. They are simply used
    as unique identifiers. This demo shows all of the basic features but others
    may be used by specific vendors.
    </p>
  </body>
</html>
